﻿//=============================================================================
// Project  : NIPO Component Framework
// File    : Plugin.cs
// Author  : Bernhard Dieber (Bernhard.Dieber@uni-klu.ac.at)
// Copyright 2010 by Bernhard Dieber
// This code is published under the Microsoft Public License (Ms-PL).  A copy
// of the license should be distributed with the code.  It can also be found
// at the project website: http://NIPO.CodePlex.com.   This notice, the
// author's name, and all copyright notices must remain intact in all
// applications, documentation, and source files.
//=============================================================================

using System;
using NIPO.Util;

namespace NIPO.Plugins
{
    /// <summary>
    /// Base class of the NIPO Plugin hierarchy<br />
    /// This class defines the most basic methods and properties that a NIPO plugin must fulfill
    /// </summary>
    public abstract class Plugin : IDisposable
    {
        private Logger _log;
        
        /// <summary>
        /// Gets or sets the Plugin-ID.
        /// </summary>
        /// <value>The ID.</value>
        public int ID { get; protected internal set; }
        
        /// <summary>
        /// A plugin must provide a name
        /// </summary>
        /// <value>The name.</value>
        public virtual String Name
        {
            get
            {
                return this.GetType().Name;
            }
        }
        
        /// <summary>
        /// Every plugin must provide a description on what it does
        /// </summary>
        /// <value>The description.</value>
        public virtual string Description
        {
            get { return "The " + Name; }
        }

        /// <summary>
        /// The ConfigurationObject is used to have a user configure a plugin.<br />
        /// Provide here a (subclass) instance of PluginConfiguration that defines the configuration values of your need
        /// </summary>
        /// <value>The configuration object.</value>
        public virtual PluginConfiguration ConfigurationObject
        {
            get;
            set;
        }

        /// <summary>
        /// Gets a value indicating whether this instance is configured.<br />
        /// "Configured" means that the plugin is ready to run and does not need any additional configuration information
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is configured; otherwise, <c>false</c>.
        /// </value>
        public abstract bool IsConfigured
        {
            get;
        }

        /// <summary>
        /// Returns a logger preconfigured for every plugin
        /// </summary>
        public Logger Log
        {
            get
            {
                lock (this)
                {

                    if (_log == null)
                        _log = new Logger(GetType().FullName + ID);
                }
                return _log;
            }
        }

        /// <summary>
        /// Opportunity for a plugin to do pre-start initialization (e.g. resource allocation, event registration, ...)<br/>
        /// This method is called immediately before the framework start (after checking that IsConfigured == <c>true</c>
        /// </summary>
        /// <remarks>Registration of non-standard events is supposed to happen here. If your plugin is supposed to catch events other than normal data events, this should be done here.</remarks>
        protected internal abstract void Initialize();

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public abstract void Dispose();

        /// <summary>
        /// Gets the version.
        /// </summary>
        /// <value>The version.</value>
        public virtual Version Version
        {
            get { return GetType().Assembly.GetName().Version; }
        }

        #region static utility function
        /// <summary>
        /// Returns a Type-object for the given ePlugInType
        /// </summary>
        /// <param eventName="type"></param>
        /// <returns></returns>
        public static Type GetType(PlugInType type)
        {
            Type searchType = typeof(Plugin);
            switch (type)
            {
                case PlugInType.Input:
                    searchType = typeof(InputPlugin);
                    break;
                case PlugInType.Output:
                    searchType = typeof(OutputPlugin);
                    break;
                case PlugInType.Processing:
                    searchType = typeof(ProcessingPlugin);
                    break;
                case PlugInType.Service:
                    searchType = typeof(ServicePlugin);
                    break;
                case PlugInType.Observer:
                    searchType = typeof(ObserverPlugin);
                    break;
            }
            return searchType;
        }

        /// <summary>
        /// Gets the pluginType for the given type-object.
        /// </summary>
        /// <remarks>This method only determines a plugintype of a concrete Plugin subclass.</remarks>
        /// <param name="pluginType">Type of the plugin.</param>
        /// <returns>A PluginType that the given <paramref name="pluginType"/> implements</returns>
        /// <exception cref="ArgumentException"><paramref name="pluginType"/> must be a subclass of Plugin</exception>
        public static PlugInType GetType(Type pluginType)
        {
            if (!pluginType.IsSubclassOf(typeof(Plugin)))
                throw new ArgumentException("Argument must be a subclass of Plugin");
            if (pluginType.IsSubclassOf(typeof(InputPlugin)))
                return PlugInType.Input;
            if (pluginType.IsSubclassOf(typeof(ProcessingPlugin)))
                return PlugInType.Processing;
            if (pluginType.IsSubclassOf(typeof(OutputPlugin)))
                return PlugInType.Output;
            if (pluginType.IsSubclassOf(typeof(ObserverPlugin)))
                return PlugInType.Observer;
            if (pluginType.IsSubclassOf(typeof(ServicePlugin)))
                return PlugInType.Service;
            return PlugInType.PlugIn;
        }
        #endregion

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return Name + " ("+Version+")";
        }
    }
}